时区问题
用 java.util.Date 配合 @JsonFormat 序列化时,时间会莫名其妙偏移(典型是少 8 小时)。
场景复现
@Setter
@Getter
class User {
private String username;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date date;
}
ObjectMapper objectMapper = new ObjectMapper();
User user = new User();
user.setUsername("zhangsan");
user.setDate(new Date()); // 系统时间 2021-09-25 10:48:30
System.out.println(objectMapper.writeValueAsString(user));
输出比系统时间少了 8 小时:
{
"username" : "zhangsan",
"date" : "2021-09-25 02:48:38"
}
换成 java.time.LocalDateTime 没这个问题,根因在时区。
原因
@JsonFormat 做日期格式化时,默认时区是 UTC,而不是 JVM 读到的操作系统时区。所以东八区的 Date 被按 UTC 格式化,正好少 8 小时。
解决
把 ObjectMapper 的默认时区设为 JVM 系统时区:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setTimeZone(TimeZone.getDefault());
用 builder 配置时对应 builder.defaultTimeZone(TimeZone.getDefault()),见 ObjectMapper 配置。
{
"username" : "zhangsan",
"date" : "2021-09-25 10:59:16"
}
为什么用 getDefault 而不是写死时区
写死成 TimeZone.getTimeZone("Asia/Shanghai") 也能解决,但不推荐。业务一旦跨地区部署(容器化部署尤其常见),给每个容器单独定制时区不现实。统一取 JVM 系统时区,让运维通过容器 / 系统时区一处控制,业务代码零改动。